package com.ttbj.product.yitong.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ttbj.api.dto.BalanceData;
import com.ttbj.api.dto.Page;
import com.ttbj.api.dto.QueryVO;
import com.ttbj.api.dto.WithdrawData;
import com.ttbj.api.exception.BusinessException;
import com.ttbj.api.yitong.WithdrawService;
import com.ttbj.api.yitong.YTFinancialService;
import com.ttbj.company.dao.CompanyMapper;
import com.ttbj.constant.Const;
import com.ttbj.constant.PlatFormErrorCode;
import com.ttbj.constant.WdNotifyEnum;
import com.ttbj.core.util.DateUtils;
import com.ttbj.core.util.DtoTransitionUtils;
import com.ttbj.core.util.JsonUtil;
import com.ttbj.core.util.RegexUtil;
import com.ttbj.driver.dao.DriverMapper;
import com.ttbj.product.util.PropertiesUtil;
import com.ttbj.product.ytpayutil.RandomCharData;
import com.ttbj.withdraw.bean.po.WdNotify;
import com.ttbj.withdraw.bean.po.WdPassword;
import com.ttbj.withdraw.bean.po.WdQuery;
import com.ttbj.withdraw.bean.po.Withdraw;
import com.ttbj.withdraw.dao.WithdrawMapper;



@Service("withdrawService")
public class WithdrawServiceImpl implements WithdrawService{
	
	@Autowired
	private WithdrawMapper withdrawMapper;
	@Autowired
	private YTFinancialService ytFinancialService;
	@Autowired
	private DriverMapper driverMapper;
	@Autowired
	private CompanyMapper companyMapper;
	
	private static final Logger logger = LoggerFactory.getLogger(WithdrawServiceImpl.class);
	
	private static final String STATUS = "status";
	private static final String RETINFO = "retInfo";
	
	@Override
	public Map<String, String> withrawOperation(String wdPassword, String accountNo, String amount, String personNum, String personName) throws Exception {
		Map<String, String> resultMap = new HashMap<>();
		String status = "0";	//设置默认值为 0表示失败，1表示成功
		resultMap.put(STATUS, status);
		if (StringUtils.isBlank(wdPassword)) {
			resultMap.put(RETINFO, "提现密码为空");
			return resultMap;
		}
		//如果账户号为空或者金额不符合格式（必须大约0，正数或者正浮点数）
		if (StringUtils.isBlank(accountNo) || !RegexUtil.amountOfMoney(amount)) {
			logger.error("错误->账户号为空或者输入的提现金额有误，账户号：{}，提现金额：{}", accountNo, amount);
			resultMap.put(RETINFO, "账户号为空或者输入的提现金额有误");
			return resultMap;
		}
		//查询出此账户号对应的加密提现密码
		WdPassword encryptionPwd = this.withdrawMapper.queryWdPasswordByAccount(accountNo);
		if (null != encryptionPwd) {
			String wdPwd = encryptionPwd.getWdPassword();
			if (StringUtils.isBlank(wdPwd)) {	//如果此账户号下的提现密码为空 ，则提示设置提现密码
				resultMap.put(RETINFO, "提现密码为空，请设置提现密码");
				return resultMap;
			}
		}else {	//如果使用账户号没有查出任何数据，则说明数据有问题
			resultMap.put(RETINFO, "无此账户号，无法提现");
			return resultMap;
		}
		//把前端输入的提现密码进行加密
		String hashInterationsPwd = (new SimpleHash(Const.algorithmName, wdPassword, personName, Const.hashIterations)).toString();
		//比对密码
		if (!encryptionPwd.getWdPassword().equals(hashInterationsPwd)) {
			resultMap.put(RETINFO, "提现密码错误！");
			return resultMap;
		}
		Withdraw withdraw = new Withdraw();
		withdraw.setAccountNo(accountNo);	//设置账号号
		//使用账户号调用余额查询接口，查询可用余额(单位:元)
		Map<String, String> map = this.ytFinancialService.getYTFinancialResult(withdraw, 20, "balance");
		String blanceStatus = map.get("status");	//获取返回的状态
		//如果返回了0，则余额查询接口返回了异常
		if (blanceStatus.equals("0")) {
			logger.info("余额查询接口异常，异常描述：{}", map.get("data").split("\\|")[1]);
			resultMap.put(RETINFO, "余额查询接口异常，异常描述：" + map.get("data").split("\\|")[1]);
			return resultMap;
		}
		//把data节点的json字符串转换成bean
		BalanceData balanceData = (BalanceData) JsonUtil.jsonToBean(map.get("data"), "data", BalanceData.class);
		//比较提现金额和可用金额，如大于可用余额
		BigDecimal amountDecimal = new BigDecimal(amount);
		BigDecimal blanceDecimal =  new BigDecimal(balanceData.getBalance());
		if (amountDecimal.compareTo(blanceDecimal) == 1) {	//如果为1，则说明提现金额大于可用余额
			logger.info("错误->提现金额大于可用余额，提现金额：{}，可用余额：{}", amount, balanceData.getBalance());
			resultMap.put(RETINFO, "提现金额大于可用余额");
			return resultMap;
		}
		map.clear();	//清空上面的map
		String reqOrderNo = "WD" + DateUtils.getCurDtsStr() + RandomCharData.createData(8);	//设置一个提现订单号（外部系统订单号）
		withdraw.setOrderNo(reqOrderNo);	//设置提现订单号（外部系统订单号）
		withdraw.setAmount(amount);
		withdraw.setBackNotifyUrl(PropertiesUtil.getInstance().getValue("wd_back_notify_url"));	//异步通知URL
		//提现操作
		map = this.ytFinancialService.getYTFinancialResult(withdraw, 20, "withdraw");
		String withdrawStatus = map.get("status");	//获取返回的状态
		//如果返回了0，则提现接口返回了异常
		if (withdrawStatus.equals("0")) {
			resultMap.put(RETINFO, "提现接口返回了异常，异常描述：" + map.get("data").split("\\|")[1]);
			return resultMap;
		}else {
			//json转换bean
			QueryVO queryVO = (QueryVO) JsonUtil.jsonToBean(map.get("data"), QueryVO.class);
			//把data节点的json字符串转换成bean
			withdraw = (Withdraw) JsonUtil.jsonToBean(map.get("data"), "data", Withdraw.class);
			withdraw.setReqTime(DateUtils.getDateTimeStr(queryVO.getReqTime()));	//设置并格式化请求时间
			withdraw.setStatus(withdrawStatus);
			withdraw.setRetCode(queryVO.getRetCode());
			withdraw.setRetInfo(queryVO.getRetInfo());
			withdraw.setReqOrderNo(reqOrderNo);//设置并保存reqOrderNo（外部系统订单号）：因为异步回调中要使用这个号进行更新提现状态
			withdraw.setPersonNum(personNum);	//保存提现人的编号
			withdraw.setPersonName(personName);	//保存提现人的账号
			logger.info("提现受理成功，提现信息：{}", withdraw.toString());
			//保存提现信息到数据库
			int i = this.withdrawMapper.insertWithdrawInfo(withdraw);
			
			status = map.get("status");
			resultMap.put(STATUS, status);
			resultMap.put(RETINFO, queryVO.getRetInfo());
			return resultMap;
		}
	}

	@Override
	public Map<String, String> withrawNotify(String noticeStr) throws Exception {
		Map<String, String> resultMap = new HashMap<>();
		String status = "0";	//设置默认值为 0表示失败，1表示成功
		resultMap.put(STATUS, status);
		Withdraw withdraw = new Withdraw();
		//将body中获取回调通知报文进行验证签名
		Map<String, String> autographMap = this.ytFinancialService.getWdNotify(noticeStr);
		//将提现验证签名成功后返回的json字符串转成bean
		WdNotify wdNotify = (WdNotify) JsonUtil.jsonToBean(autographMap.get("data"), WdNotify.class);
		logger.info("提现异步通知返回的数据：{}", wdNotify);
		//如果返回了0，则说明验证签名失败，则status保存为02
		if ("0".equals(autographMap.get("status"))) {
			logger.info("提现回调通知报文进行验证签名失败");
			withdraw.setStatus(WdNotifyEnum.FAIL.getCode());
			withdraw.setRetInfo("验签失败");
			resultMap.put(RETINFO, "验证签名不通过");
		}else {	//验证签名通过
			String notifyStatus = wdNotify.getSTATUS();	//获取异步通知返回的提现状态：00：成功，01：失败，02处理中，03：待请求，04：网络异常
			String retInfo = null;
			if (notifyStatus.equals(WdNotifyEnum.SUCCESS.getCode())) {
				retInfo = WdNotifyEnum.SUCCESS.getDesc();
			}else if (notifyStatus.equals(WdNotifyEnum.FAIL.getCode())) {
				retInfo = WdNotifyEnum.FAIL.getDesc();
			}else if (notifyStatus.equals(WdNotifyEnum.HANDING.getCode())) {
				retInfo = WdNotifyEnum.HANDING.getDesc();
			}else if (notifyStatus.equals(WdNotifyEnum.PENDING_REQUEST.getCode())) {
				retInfo = WdNotifyEnum.PENDING_REQUEST.getDesc();
			}else {
				retInfo = WdNotifyEnum.NETWORK_ANOMALY.getDesc();
			}
			withdraw.setStatus(notifyStatus);
			withdraw.setRetInfo(retInfo);
			resultMap.put(STATUS, "1");
		}
		withdraw.setReqOrderNo(wdNotify.getORDERNO());
		//通过提现异步通知返回的ORDERNO（提现订单号（外部系统））来更新status（提现状态）和 提现描述（retInfo）
		int i = this.withdrawMapper.updateStatusAndRetInfoByOrderNo(withdraw);
		if (i == 0) {
			logger.info("提现成功，更新status和retInfo失败，数据：{}", withdraw.toString());
			resultMap.put(STATUS, "2");
			resultMap.put(RETINFO, "提现成功，更新状态值失败");
			return resultMap;
		}
		resultMap.put(RETINFO, "提现成功");
		return resultMap;
	}

	@Override
	public Map<String, String> withrawBalance(String accountNo) throws Exception {
		Map<String, String> resultMap = new HashMap<>();
		String status = "0";	//设置默认值为 0表示失败，1表示成功
		resultMap.put(STATUS, status);
		if (StringUtils.isBlank(accountNo)) {
			resultMap.put(RETINFO, "没有账户号，不能余额查询");
			return resultMap;
		}
		BalanceData balance = new BalanceData();
		balance.setAccountNo(accountNo);	//设置账户号
		//调用易通金服余额查询接口
		Map<String, String> balanceMap = this.ytFinancialService.getYTFinancialResult(balance, 20, "balance");
		//如果status为1，则说明请求接口成功，返回balance，billAmt，frozenAmt信息
		if (balanceMap.get("status").equals("1")) {
			balance = (BalanceData) JsonUtil.jsonToBean(balanceMap.get("data"), "data", BalanceData.class);
			resultMap.put("balance", balance.getBalance());	//可用余额
			resultMap.put("billAmt", balance.getBillAmt());	//挂账金额
			resultMap.put("frozenAmt", balance.getFrozenAmt());	//冻结金额
			resultMap.put(STATUS, "1");
			resultMap.put(RETINFO, "受理成功");
		}else {	//如果status为0，则说明请求接口有异常，返回异常描述
			resultMap.put(RETINFO, balanceMap.get("data").split("\\|")[1]);
		}
		return resultMap;
	}

	@Override
	public Map<String, String> withrawQuery(String accountNo, String orderNo, String status) throws Exception {
		Map<String, String> resultMap = new HashMap<>();
		String resultStatus = "0";	
		resultMap.put(STATUS, resultStatus);
		//判断传的参数是否为null或者空
		if (StringUtils.isBlank(accountNo) || StringUtils.isBlank(orderNo) || StringUtils.isBlank(status)) {
			resultMap.put(RETINFO, "参数不能为空");
			return resultMap;
		}
		WdQuery wdQuery = new WdQuery();
		wdQuery.setAccountNo(accountNo);	//设置账户号
		wdQuery.setOrderNo(orderNo);	//设置提现订单号（分账系统订单号）
		//使用提现查询接口查询提现状态
		Map<String, String> wdQueryMap = this.ytFinancialService.getYTFinancialResult(wdQuery, 20, "wd_query");
		if (wdQueryMap.get("status").equals("1")) {	//如果是请求接口成功
			wdQuery = (WdQuery) JsonUtil.jsonToBean(wdQueryMap.get("data"), "data", WdQuery.class);
			String retInfo = null;	//提现描述
			//如果查询的状态跟前台传来的状态不同的话，则更新状态
			if (!status.equals(wdQuery.getStatus())) {
				String queryStatus = wdQuery.getStatus();
				if (queryStatus.equals(WdNotifyEnum.SUCCESS.getCode())) {
					retInfo = WdNotifyEnum.SUCCESS.getDesc();
				}else if (queryStatus.equals(WdNotifyEnum.FAIL.getCode())) {
					retInfo = WdNotifyEnum.FAIL.getDesc();
				}else if (queryStatus.equals(WdNotifyEnum.HANDING.getCode())) {
					retInfo = WdNotifyEnum.HANDING.getDesc();
				}else if (queryStatus.equals(WdNotifyEnum.PENDING_REQUEST.getCode())) {
					retInfo = WdNotifyEnum.PENDING_REQUEST.getDesc();
				}else {
					retInfo = WdNotifyEnum.NETWORK_ANOMALY.getDesc();
				}
				//更新提现状态值和提现描述
				int i = this.withdrawMapper.updateStatusAndInfo(wdQuery.getStatus(), retInfo, orderNo);
				resultMap.put(RETINFO, retInfo);
			}else {
				resultMap.put(RETINFO, "受理成功");
			}
			resultMap.put(STATUS, "1");
			resultMap.put("wdQueryStatus", wdQuery.getStatus());
		}else {	//如果是请求接口出现异常，则返回一个异常描述
			resultMap.put(RETINFO, wdQueryMap.get("data").split("\\|")[1]);
		}
		return resultMap;
	}
	
	@Override
	@Transactional
	public void setUpDriverWdPassword(String driverNum, String driverName, String wdPassword) throws BusinessException {
		if (StringUtils.isBlank(driverNum) || StringUtils.isBlank(driverName) || StringUtils.isBlank(wdPassword)) {
			throw new BusinessException("司机编号或司机用户名或提现密码不能为空！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		//使用纯6位数字密码
		Pattern pattern = Pattern.compile("^\\d{6}$");
		boolean matches = pattern.matcher(wdPassword).matches();
		if (!matches) {
			throw new BusinessException("请使用6位纯数字密码！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//设置提现加密密码
		String hashInterationsPwd = (new SimpleHash(Const.algorithmName, wdPassword, driverName, Const.hashIterations)).toString();
		//通过编号保存提现密码
		int i = this.driverMapper.updateDriverWdPasswordByNum(hashInterationsPwd, driverNum);
		if (i == 0) {
			throw new BusinessException("提现密码保存失败！", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}
	
	@Override
	@Transactional
	public void modifyDriverWdPassword(String driverNum, String driverName, String oldWdPassword, String newWdPassword)
			throws BusinessException {
		if (StringUtils.isBlank(driverNum) || StringUtils.isBlank(driverName) || StringUtils.isBlank(oldWdPassword) 
				|| StringUtils.isBlank(newWdPassword)) {
			throw new BusinessException("司机编号或司机用户名或提现密码为空！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		//使用纯6位数字密码
		Pattern pattern = Pattern.compile("^\\d{6}$");
		boolean matches1 = pattern.matcher(oldWdPassword).matches();
		boolean matches2 = pattern.matcher(newWdPassword).matches();
		if (!matches1 || !matches2) {
			throw new BusinessException("请使用6位纯数字密码！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//加密旧密码
		String hashInterationsOldPwd1 = (new SimpleHash(Const.algorithmName, oldWdPassword, driverName, Const.hashIterations)).toString();
		//从数据库中获取旧密码
		String hashInterationsOldPwd2 = this.driverMapper.queryDriverWdPasswordByNum(driverNum);
		//如果相等，则旧密码正确，否则旧密码输入不正确
		if (!hashInterationsOldPwd1.equals(hashInterationsOldPwd2)) {
			throw new BusinessException("旧密码不正确！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//重新设置新密码
		String nHashInterationsPwd = (new SimpleHash(Const.algorithmName, newWdPassword, driverName, Const.hashIterations)).toString();
		//更新设置好的新密码
		int i = this.driverMapper.updateDriverWdPasswordByNum(nHashInterationsPwd, driverNum);
		if (i == 0) {
			throw new BusinessException("提现密码保存失败！", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}
	
	@Override
	@Transactional
	public void setUpComnumWdPassword(String comnumNum, String salesmanName, String wdPassword)
			throws BusinessException {
		if (StringUtils.isBlank(comnumNum) || StringUtils.isBlank(salesmanName) || StringUtils.isBlank(wdPassword)) {
			throw new BusinessException("企业编号或企业用户名或提现密码不能为空！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		//使用纯6位数字密码
		Pattern pattern = Pattern.compile("^\\d{6}$");
		boolean matches = pattern.matcher(wdPassword).matches();
		if (!matches) {
			throw new BusinessException("请使用6位纯数字密码！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//设置提现加密密码
		String hashInterationsPwd = (new SimpleHash(Const.algorithmName, wdPassword, salesmanName, Const.hashIterations)).toString();
		//保存提现密码
		int i = this.companyMapper.updateWdPasswordByNum(hashInterationsPwd, comnumNum);
		if (i == 0) {
			throw new BusinessException("提现密码保存失败！", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}
	
	@Override
	@Transactional
	public void modifyComnumWdPassword(String comnumNum, String salesmanName, String oldWdPassword, String newWdPassword)
			throws BusinessException {
		if (StringUtils.isBlank(comnumNum) || StringUtils.isBlank(salesmanName) || StringUtils.isBlank(oldWdPassword) 
				|| StringUtils.isBlank(newWdPassword)) {
			throw new BusinessException("企业编号或企业用户名或提现密码为空！", PlatFormErrorCode.PARAM_IS_NULL.code());
		}
		//使用纯6位数字密码
		Pattern pattern = Pattern.compile("^\\d{6}$");
		boolean matches1 = pattern.matcher(oldWdPassword).matches();
		boolean matches2 = pattern.matcher(newWdPassword).matches();
		if (!matches1 || !matches2) {
			throw new BusinessException("请使用6位纯数字密码！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//加密旧密码
		String hashInterationsOldPwd1 = (new SimpleHash(Const.algorithmName, oldWdPassword, salesmanName, Const.hashIterations)).toString();
		//从数据库中获取旧密码
		String hashInterationsOldPwd2 = this.companyMapper.queryWdPasswordByNum(comnumNum);
		//如果相等，则旧密码正确，否则旧密码输入不正确
		if (!hashInterationsOldPwd1.equals(hashInterationsOldPwd2)) {
			throw new BusinessException("旧密码不正确！", PlatFormErrorCode.DATA_SECURITY.code());
		}
		//重新设置新密码
		String nHashInterationsPwd = (new SimpleHash(Const.algorithmName, newWdPassword, salesmanName, Const.hashIterations)).toString();
		//更新设置好的新密码
		int i = this.companyMapper.updateWdPasswordByNum(nHashInterationsPwd, comnumNum);
		if (i == 0) {
			throw new BusinessException("提现密码保存失败！", PlatFormErrorCode.DATA_SECURITY.code());
		}
	}
	
	@Override
	public List<WithdrawData> findWithdrawResultByPage(WithdrawData wData, Page page) throws BusinessException {
		if (null == wData) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code());
		}
		Withdraw withdraw = (Withdraw) DtoTransitionUtils.trans(Withdraw.class, wData);
		List<Withdraw> withdraws = this.withdrawMapper.queryWithdrawResultInfoByPage(withdraw, page);
		List<WithdrawData> withdrawDatas = new ArrayList<>();
		for(Withdraw withdraw2 : withdraws) {
			WithdrawData wData2 = (WithdrawData) DtoTransitionUtils.trans(WithdrawData.class, withdraw2);
			withdrawDatas.add(wData2);
		}
		return withdrawDatas;
	}

	@Override
	public Integer findWithdrawResultByPageCount(WithdrawData wData) throws BusinessException {
		if (null == wData) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code());
		}
		Withdraw withdraw = (Withdraw) DtoTransitionUtils.trans(Withdraw.class, wData);
		Integer count = this.withdrawMapper.queryWithdrawResultInfoByPageCount(withdraw);
		return count;
	}

	@Override
	public List<WithdrawData> findWithdrawLogByPage(WithdrawData wData, Page page) throws BusinessException {
		if (null == wData) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code());
		}
		Withdraw withdraw = (Withdraw) DtoTransitionUtils.trans(Withdraw.class, wData);
		List<Withdraw> withdraws = this.withdrawMapper.queryWithdrawLogByPage(withdraw, page);
		List<WithdrawData> withdrawDatas = new ArrayList<>();
		for(Withdraw withdraw2 : withdraws) {
			WithdrawData wData2 = (WithdrawData) DtoTransitionUtils.trans(WithdrawData.class, withdraw2);
			withdrawDatas.add(wData2);
		}
		return withdrawDatas;
	}

	@Override
	public Integer findWithdrawLogByPageCount(WithdrawData wData) throws BusinessException {
		if (null == wData) {
			throw new BusinessException("数据有错误！", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code());
		}
		Withdraw withdraw = (Withdraw) DtoTransitionUtils.trans(Withdraw.class, wData);
		Integer count = this.withdrawMapper.queryWithdrawLogByPageCount(withdraw);
		return count;
	}
}
